home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / pas / swag / datetime.swg / 0034_Clock & Timer Unit.pas < prev    next >
Pascal/Delphi Source File  |  1994-02-03  |  19KB  |  526 lines

  1. UNIT Clocks;
  2.  
  3.  {This UNIT provides a CLOCK OBJECT for use in Turbo Pascal 5.5.
  4.  
  5.   (C) Copyright 1989, Earl F. Glynn, Overland Park, KS.  Compuserve 73257,3527.
  6.   All Rights Reserved.  This Turbo Pascal 5.5 UNIT may be freely distributed
  7.   for non-commerical use.
  8.  
  9.   Clock objects can be used as individual timers, using either the CMOS
  10.   real-time clock, or the DOS real-time clock.  As shown in the ClkDemo
  11.   PROGRAM, the DOS clock can be shut off when interrupts are disabled.
  12.   The resolution of the CMOS clock is only 1 second, while the DOS clock
  13.   has 0.0549 second resolution (18.203 ticks per second).  In addition
  14.   to real-time clocks, static time stamps can be manipulated and
  15.   formatted.  The range for all clocks and time stamps is Jan 1, 1900
  16.   through Jun 5, 2079.  (Sep 18, 1989 is the midpoint of this range).
  17.  
  18.   Several REXX-like FUNCTIONs provide Date/Time formatting.  [REXX,
  19.   the Restructured Extended Executor, or sometimes called the System Product
  20.   Interpreter, is IBM's SAA command language (now primarily for VM/CMS).
  21.   That is, REXX EXECs are CMS's equivalent of PC .BAT files but REXX
  22.   provides much more functionality than the PC 'BAT' language.]
  23.  
  24.   REXX-like FUNCTIONS in Pascal could be considered an oxymoron since
  25.   REXX doesn't have any concept of TYPEd variables and obviously Pascal does.
  26.   The Pascal functions in most cases were written to return STRINGs,
  27.   which is similar to REXX.  In some cases, where a number was returned
  28.   that could be used in calculations, a separate function was used.  For
  29.   example, the REXX TIME('Elapsed') function was implemented as an object
  30.   'Elapsed' method that returns a REAL value to be used in calculations.
  31.   A function 'hhmmss' can be used to format elapsed seconds in a
  32.   character string, if desired.
  33.  
  34.   See the CLKDEMO.PAS, FLOPS.PAS and TIMER.PAS programs for sample usage
  35.   of clock objects and this UNIT.}
  36.  
  37. INTERFACE
  38.  
  39.   TYPE
  40.     ClockValue    =
  41.       RECORD
  42.         year      :  1900..2079;
  43.         month     :  1..12;
  44.         day       :  1..31;
  45.         hour      :  0..23;
  46.         minute    :  0..59;
  47.         second    :  0..59;
  48.         hundredth :  0..99;
  49.       END;
  50.     ClockType     =  (CMOSClock,DOSClock);
  51.     Clock         =
  52.       OBJECT
  53.         mode      :  ClockType;
  54.         StartValue:  ClockValue;
  55.         FUNCTION  Date(s:  STRING):  STRING;
  56.         FUNCTION  Elapsed:  REAL;   {elapsed timer (seconds)}
  57.         PROCEDURE Start (ct:  ClockType);
  58.         FUNCTION  Time(s:  STRING):  STRING;
  59.       END;
  60.  
  61.   FUNCTION  DateFormat(s:  STRING; clk:  ClockValue):  STRING;
  62.   FUNCTION  DaysThisCentury(y, m, d:  WORD):  WORD;
  63.   FUNCTION  hhmmss(seconds:  REAL):  STRING;
  64.   FUNCTION  JulianDate(y{1900..}, m{1..12}, d{1..31}:  WORD):  WORD;
  65.   PROCEDURE SetClock (yr,mo,d,h,m,s,hth:  WORD; VAR t:  ClockValue);
  66.   FUNCTION  TimeDiff(t2,t1:  ClockValue):  REAL;  {t2 - t1 seconds}
  67.   FUNCTION  TimeFormat(s:  STRING; clk:  ClockValue):  STRING;
  68.   PROCEDURE UnPackTime (TurboTime:  LongInt; VAR Clk:  ClockValue);
  69.  
  70. IMPLEMENTATION
  71.  
  72.   USES
  73.     DOS; {INTR}
  74.  
  75.   VAR
  76.     c  :  CHAR;
  77.  
  78.   FUNCTION L2C(L:  LONGINT):  STRING;  {LONGINT-to-character}
  79.     {L2C and W2C are intended to be similar to the standard D2C
  80.      (decimal-to-character) REXX function.}
  81.     VAR t:  STRING[11];
  82.   BEGIN
  83.     STR (L,t);
  84.     L2C := t
  85.   END {L2C};
  86.  
  87.   FUNCTION W2C(w:  WORD):  STRING;     {word-to-character}
  88.     VAR t:  STRING[5];
  89.   BEGIN
  90.     STR (w,t);
  91.     W2C := t
  92.   END {W2C};
  93.  
  94.   FUNCTION TwoDigits (w:  WORD):  STRING;
  95.     CONST Digit:  ARRAY[0..9] OF CHAR = '0123456789';
  96.   BEGIN
  97.     w := w MOD 100;  {just to be safe}
  98.     TwoDigits := Digit[w DIV 10] + Digit[w MOD 10]
  99.   END {TwoDigits};
  100.  
  101.   FUNCTION DateFormat(s:  STRING; clk:  ClockValue):  STRING;
  102.     CONST
  103.       days  :  ARRAY[0..6] OF STRING[9]
  104.                          =('Sunday','Monday','Tuesday','Wednesday',
  105.                            'Thursday','Friday','Saturday');
  106.       months:  ARRAY[1..12] OF STRING[9]
  107.                          =('January','February','March',
  108.                            'April',  'May',     'June',
  109.                            'July',   'August',  'September',
  110.                            'October','November','December');
  111.   BEGIN
  112.     IF   LENGTH(s) = 0
  113.     THEN c := 'N' {NORMAL}
  114.     ELSE c := UpCase(s[1]);
  115.     CASE c OF
  116.             {Normal (default):  dd Mmm yyyy -- no leading zero or blank}
  117.       'N':  DateFormat := W2C(clk.day) + ' ' + COPY(months[clk.month],1,3)
  118.                                        + ' ' + W2C(clk.year);
  119.  
  120.             {Century:  ddddd -- no leading zeros or blanks}
  121.       'C':  DateFormat := W2C( DaysThisCentury(clk.year,clk.month,clk.day) );
  122.  
  123.             {Julian date:  ddd -- no leading 0s or blanks}
  124.       'D':  DateFormat := W2C(JulianDate(clk.year,clk.month,clk.day));
  125.  
  126.             {European:  dd/mm/yy}
  127.       'E':  DateFormat := TwoDigits(clk.day  )  + '/' +
  128.               TwoDigits(clk.month)  + '/' + TwoDigits(clk.year MOD 100);
  129.  
  130.             {Month:  current month name in mixed case}
  131.       'M':  DateFormat := months[clk.month];
  132.  
  133.             {Ordered:  yy/mm/dd suitable for sorting}
  134.       'O':  DateFormat := TwoDigits(clk.year MOD 100)  + '/' +
  135.               TwoDigits(clk.month)  + '/' + TwoDigits(clk.day);
  136.  
  137.             {Standard:  yyyymmdd -- suitable for sorting (ISO/R 2014-1971)}
  138.       'S':  DateFormat := W2C(clk.year) + TwoDigits(clk.month) +
  139.               TwoDigits(clk.day);
  140.  
  141.             {USA:  mm/dd/yy}
  142.       'U':  DateFormat := TwoDigits(clk.month)  + '/' +
  143.               TwoDigits(clk.day  )  + '/' + TwoDigits(clk.year MOD 100);
  144.  
  145.             {Weekday:  returns day of the week in mixed case}
  146.       'W':  DateFormat :=  {January 1, 1900 was a Monday}
  147.               days[DaysThisCentury(clk.year,clk.month,clk.day) MOD 7 ]
  148.  
  149.       ELSE DateFormat := ''
  150.     END
  151.   END {DateFormat};
  152.  
  153.   FUNCTION DaysThisCentury(y, m, d:  WORD):  WORD;
  154.  
  155.   {This function was written to be equivalent to the REXX language
  156.    DATE('Century') function.  See DateFormat FUNCTION in this UNIT.
  157.  
  158.    Jan 1, 1900 = 1, Jan 2, 1900 = 2, ..., Jun 5, 2079 = 65535 (largest word).
  159.    Jan 1, 1989 = 32508, Jan 1, 1990 = 32873, Sep 18, 1989 = 32768.
  160.  
  161.    "The Astronomical Almanac" defines the astronomical julian date
  162.    to be the numbers of mean solar days since 4713 BC.  In this system
  163.    Jan 1, 1900 = 2415020.5, Jan 1, 2000 = 2451544.5,
  164.    Jan 1, 1989 = 2447527.5, Jan 1, 1990 = 2447892.5,
  165.    Jun 5, 2079 = 2480554.5.  This data was used to validate the function.
  166.  
  167.    (Note:  DaysThisCentry(y,m,d) MOD 7  returns day-of-week index, i.e.,
  168.    0=Sunday, 1=Monday, etc. since January 1, 1900 was a Monday.)}
  169.   BEGIN
  170.     DaysThisCentury := 365*(y-1900) + INTEGER(y-1901) DIV 4 + JulianDate(y,m,d)
  171.   END {DaysThisCentury};
  172.  
  173.   FUNCTION  hhmmss(seconds:  REAL):  STRING;
  174.     {Convert elapsed times/time differences to [hh:]mm:ss format}
  175.     VAR
  176.       h,h1,h2:  LONGINT;
  177.       s      :  STRING;
  178.       t      :  LONGINT;
  179.   BEGIN
  180.     IF   seconds < 0.0
  181.     THEN BEGIN
  182.       seconds := ABS(seconds);
  183.       s := '-'
  184.     END
  185.     ELSE s:= '';
  186.     h1 := 0;
  187.     WHILE seconds > 2147483647.0 DO BEGIN  {fixup real-to-LONGINT problem}
  188.       seconds := seconds - 1576800000.0;   {subtract about 50 years}
  189.       h1 := h1 + 438000 {hours}            {add about 50 years}
  190.     END;
  191.     t := TRUNC(seconds);
  192.     h2 := t DIV 3600;  {hours}
  193.     h := h1 + h2;
  194.     IF   h > 0
  195.     THEN s := s + L2C(h) + ':';
  196.     t := t - h2*3600;  {minutes and seconds left}
  197.     hhmmss := s + TwoDigits(t DIV 60) + ':' + TwoDigits(t MOD 60)
  198.   END {hhmmss};
  199.  
  200.   FUNCTION JulianDate(y{1900..}, m{1..12}, d{1..31}:  WORD):  WORD;
  201.     CONST
  202.       julian:  ARRAY[0..12] OF WORD =
  203.                (0,31,59,90,120,151,181,212,243,273,304,334,365);
  204.     VAR
  205.       jd:  WORD;
  206.   BEGIN
  207.     jd := julian[m-1] + d;
  208.     IF   (m > 2) AND (y MOD 4 = 0) AND
  209.          (y <> 1900) {AND (y <> 2100)}
  210.     THEN INC (jd);   {1900 and 2100 are not leap years; 2000 is}
  211.     JulianDate := jd
  212.   END {JulianDate};
  213.  
  214.   PROCEDURE SetClock (yr,mo,d,h,m,s,hth:  WORD; VAR t:  ClockValue);
  215.   BEGIN
  216.     t.year      := yr;
  217.     t.month     := mo;
  218.     t.day       := d;
  219.     t.hour      := h;
  220.     t.minute    := m;
  221.     t.second    := s;
  222.     t.hundredth := hth
  223.   END {SetClock};
  224.  
  225.   FUNCTION  TimeDiff(t2,t1:  ClockValue):  REAL;
  226.   BEGIN  {REAL arithmetic is used to avoid INTEGER/LONGINT overflows}
  227.     TimeDiff :=   0.01*INTEGER(t2.hundredth - t1.hundredth) +
  228.                        INTEGER(t2.second - t1.second      ) +
  229.                   60.0*INTEGER(t2.minute - t1.minute      ) +
  230.                 3600.0*INTEGER(t2.hour   - t1.hour        ) +
  231.                86400.0*LONGINT(DaysThisCentury(t2.year,t2.month,t2.day) -
  232.                        LONGINT(DaysThisCentury(t1.year,t1.month,t1.day)))
  233.   END {TimeDiff};
  234.  
  235.   FUNCTION  TimeFormat(s:  STRING; clk:  ClockValue):  STRING;
  236.     VAR
  237.       meridian:  STRING[2];
  238.   BEGIN
  239.     IF   LENGTH(s) = 0
  240.     THEN c := 'N' {NORMAL}
  241.     ELSE c := UpCase(s[1]);
  242.     CASE c OF
  243.  
  244.             {Normal (default):  hh:mm:ss}
  245.       'N':  TimeFormat := TwoDigits(clk.hour  )  + ':' +
  246.               TwoDigits(clk.minute)  + ':' + TwoDigits(clk.second);
  247.  
  248.             {Civil:  hh:mxx, for example:  11:59pm}
  249.       'C':  BEGIN
  250.               IF   clk.hour < 12
  251.               THEN BEGIN
  252.                 meridian := 'am';  {anti meridiem}
  253.                 IF   clk.hour = 0
  254.                 THEN clk.hour := 12;  {12:00am is midnight}
  255.               END                     {12:00pm is noon}
  256.               ELSE BEGIN
  257.                 meridian := 'pm';  {post meridiem}
  258.                 IF   clk.hour > 12
  259.                 THEN clk.hour := clk.hour - 12
  260.               END;
  261.               TimeFormat := W2C(clk.hour)  + ':' +
  262.                 TwoDigits(clk.minute)  + meridian
  263.             END;
  264.  
  265.             {Hours:  hh -- number of hours since midnight}
  266.       'H':  TimeFormat := W2C(clk.hour);
  267.  
  268.             {Long:  hh.mm:ss.xx (real REXX requires microseconds here)}
  269.       'L':  TimeFormat := TwoDigits(clk.hour  )  + ':' +
  270.               TwoDigits(clk.minute)  + ':' + TwoDigits(clk.second)  + '.' +
  271.               TwoDigits(clk.hundredth);
  272.  
  273.             {Minutes:  mmmm -- number of minutes since midnight}
  274.       'M':  TimeFormat := W2C(60*clk.hour + clk.minute);
  275.  
  276.             {Seconds:  sssss -- number of seconds since midnight}
  277.       'S':  TimeFormat := L2C( 3600*LONGINT(clk.hour)
  278.                + 60*LONGINT(clk.minute) + LONGINT(clk.second) )
  279.  
  280.       ELSE TimeFormat := ''
  281.     END
  282.   END {TimeFormat};
  283.  
  284.   PROCEDURE UnPackTime (TurboTime:  LongInt; VAR Clk:  ClockValue);
  285.     {The DOS.DateTime TYPE does not have hundredths of a second in its
  286.      definition.  Clocks.UnPackTime allows the use of Clocks.DateFormat
  287.      and Clocks.TimeFormat with time stamps, especially with SearchRec
  288.      TYPEed variables defined by FindFirst/FindNext.}
  289.     VAR
  290.       DT:  DateTime;
  291.   BEGIN
  292.     DOS.UnPackTime (TurboTime, DT);
  293.     SetClock (DT.year,DT.month,DT.day,DT.hour,DT.min,DT.sec,0, Clk)
  294.   END {UnPackTime};
  295.  
  296.   PROCEDURE GetDateTime (VAR c:  ClockValue; ct:  ClockType);
  297.     VAR r1,r2:  Registers;
  298.  
  299.     FUNCTION BCD (k:  BYTE):  WORD;    {convert binary-coded decimal}
  300.     BEGIN
  301.       BCD := 10*(k DIV 16) + (k MOD 16)
  302.     END {BCD};
  303.  
  304.   BEGIN
  305.     CASE ct OF
  306.       CMOSClock:
  307.         BEGIN
  308.           r1.AH := $04;
  309.           INTR ($1A,r1);      {BIOS call:  read date from real-time clock}
  310.           r2.AH := $02;
  311.           Intr ($1A,r2);      {BIOS call:  read real-time clock}
  312.           SetClock (100*BCD(r1.CH) + BCD(r1.CL) {yr},
  313.                     BCD(r1.DH) {mo}, BCD(r1.DL) {day},
  314.                     BCD(r2.CH) {h},  BCD(r2.CL) {m}, BCD(r2.DH) {s},
  315.                     0 {.00}, c)
  316.         END;
  317.       DOSClock:
  318.         BEGIN
  319.           r1.AH := $2A;       {could use GetDate and GetTime from DOS UNIT}
  320.           INTR ($21,r1);      {DOS call:  get system date}
  321.           r2.AH := $2C;
  322.           Intr ($21,r2);      {DOS call:  get system time}
  323.           SetClock (r1.CX,r1.DH,r1.DL, r2.CH,r2.CL,r2.DH,r2.DL, c)
  324.         END
  325.     END
  326.   END {GetDateTime};
  327.  
  328.   FUNCTION Clock.Date(s:  STRING):  STRING;
  329.   BEGIN
  330.     Date := DateFormat(s,StartValue)
  331.   END {Date};
  332.  
  333.   FUNCTION  Clock.Elapsed:  REAL;
  334.     VAR now:  ClockValue;
  335.   BEGIN
  336.     GetDateTime (now,mode);
  337.     Elapsed := TimeDiff(now,StartValue)
  338.   END {Clock.Elapsed};
  339.  
  340.   PROCEDURE Clock.Start (ct:  ClockType);
  341.   BEGIN
  342.     mode := ct;
  343.     GetDateTime (StartValue, ct)
  344.   END {Clock.Start};
  345.  
  346.   FUNCTION Clock.Time(s:  STRING):  STRING;
  347.   BEGIN
  348.     Time := TimeFormat(s,StartValue)
  349.   END {Time};
  350.  
  351. END {Clocks}.
  352.  
  353. {---------------------------  DEMO --------------------------}
  354.  
  355. PROGRAM ClkDemo;
  356.  
  357.  {This PROGRAM demonstates how to use the CLOCKS UNIT, including a
  358.   clock object, its methods, and related FUNCTIONs and PROCEDUREs.
  359.   Differences between CMOS and DOS clocks are shown.
  360.  
  361.   (C) Copyright 1989, Earl F. Glynn, Overland Park, KS.  Compuserve 73257,3527.
  362.   All Rights Reserved.  This Turbo Pascal 5.5 PROGRAM may be freely distributed
  363.   for non-commerical use.
  364.  
  365.   Several of the examples were derived from "The REXX Language" by
  366.   M.F. Cowlishaw, Prentice Hall, 1985.}
  367.  
  368.   USES
  369.     CRT,
  370.     Clocks,
  371.     DOS;    {FindFirst,FindNext,SearchRec,AnyFile,DOSError}
  372.  
  373.   VAR
  374.     Clk1,Clk2,Clk3:  Clock;       {clock objects -- real time clocks}
  375.     stamp1,stamp2 :  ClockValue;  {static clocks -- time stamps}
  376.     stamp3,stamp4 :  ClockValue;
  377.     stamp5        :  ClockValue;
  378.     DirInfo       :  SearchRec;
  379.  
  380.   PROCEDURE ShowClocks;
  381.   BEGIN
  382.     Clk2.Start (CMOSClock);
  383.     Clk3.Start (DOSClock);
  384.     WRITELN ('  CMOS Clock:  ',Clk2.date('u'),' ',Clk2.time('N') );
  385.     WRITELN ('   DOS Clock:  ',Clk3.date('u'),' ',Clk3.time('L') );
  386.     WRITELN ('  Difference:  ',TimeDiff(Clk2.StartValue,Clk3.StartValue):8:2,
  387.              ' second(s)');
  388.   END {ShowClocks};
  389.  
  390.   PROCEDURE DisableInterrupts;
  391.     INLINE ($FA);
  392.  
  393.   PROCEDURE EnableInterrupts;
  394.     INLINE ($FB);
  395.  
  396.   PROCEDURE KillTime;
  397.     {The following could be used for a 5-second delay, but it re-enables
  398.      interrupts when they are disabled:
  399.  
  400.         WHILE clk1.elapsed < 5.0 DO (* nothing *);
  401.  
  402.      So,time will be wasted with a few calculations.}
  403.  
  404.     VAR
  405.       i:  WORD;
  406.       x:  REAL;
  407.   BEGIN
  408.     WRITELN ('''Kill'' some time ...');
  409.     FOR i := 1 TO 10000 DO
  410.       x := SQRT(i)
  411.   END;
  412.  
  413. BEGIN
  414.   Clk1.Start (CMOSClock);
  415.   WRITELN ('CMOS/DOS Clock Differences');
  416.   WRITELN ('--------------------------');
  417.   WRITELN ('Start Clocks');
  418.   ShowClocks;
  419.   KillTime;
  420.   ShowClocks;
  421.   WRITELN ('Disable Interrupts (DOS clock will stop):');
  422.   DisableInterrupts;
  423.   KillTime;
  424.   ShowClocks;
  425.   WRITELN ('Enable Interrupts');
  426.   EnableInterrupts;
  427.  
  428.   SetClock (1985,8,27, 16,54,22, 12, stamp1);  {These are not real-time clocks.}
  429.   SetClock (1900,1, 1,  0, 0, 0,  0, stamp2);
  430.   SetClock (2079,6, 5, 23,59,59, 99, stamp3);
  431.  
  432.   WRITELN ('Cowlishaw''s':52);
  433.   WRITELN ('now':39,'REXX Book':13,'First':13,'Last':13);
  434.   WRITELN ('Date/DateFormat Examples');
  435.   WRITELN ('------------------------');
  436.   WRITELN ('day this century - C':26,Clk2.Date('Century'):13,
  437.     DateFormat('C',stamp1):13, DateFormat('C',stamp2):13,
  438.     DateFormat('C',stamp3):13);
  439.   WRITELN ('day this year - D':26,   Clk2.Date('Days'):13,
  440.     DateFormat('D',stamp1):13, DateFormat('D',stamp2):13,
  441.     DateFormat('D',stamp3):13);
  442.   WRITELN ('dd/mm/yy - E':26,        Clk2.Date('European'):13,
  443.     DateFormat('E',stamp1):13, DateFormat('E',stamp2):13,
  444.     DateFormat('E',stamp3):13);
  445.   WRITELN ('month name - M':26,      Clk2.Date('MONTH'):13,
  446.     DateFormat('M',stamp1):13, DateFormat('M',stamp2):13,
  447.     DateFormat('M',stamp3):13);
  448.   WRITELN ('dd Mmm yyyy - N':26,     Clk2.Date('normal'):13,
  449.     DateFormat('N',stamp1):13, DateFormat('N',stamp2):13,
  450.     DateFormat('N',stamp3):13);
  451.   WRITELN ('yy/mm/dd - O':26,        Clk2.Date('Ordered'):13,
  452.      DateFormat('O',stamp1):13,DateFormat('O',stamp2):13,
  453.      DateFormat('O',stamp3):13);
  454.   WRITELN ('yyyymmdd - S':26,        Clk2.Date('standard'):13,
  455.     DateFormat('S',stamp1):13, DateFormat('S',stamp2):13,
  456.     DateFormat('S',stamp3):13);
  457.   WRITELN ('mm/dd/yy - U':26,        Clk2.Date('USA'):13,
  458.     DateFormat('U',stamp1):13, DateFormat('U',stamp2):13,
  459.     DateFormat('U',stamp3):13);
  460.   WRITELN ('day of week - W':26,     Clk2.Date('weekday'):13,
  461.     DateFormat('W',stamp1):13, DateFormat('W',stamp2):13,
  462.     DateFormat('W',stamp3):13);
  463.  
  464.   WRITELN;
  465.   WRITELN ('Time/TimeFormat Examples');
  466.   WRITELN ('------------------------');
  467.   WRITELN ('hh:mmxm - C':26,             Clk2.Time('Civil'):13,
  468.     TimeFormat('C',stamp1):13, TimeFormat('C',stamp2):13,
  469.     TimeFormat('C',stamp3):13);
  470.   WRITELN ('hours since midnight - H':26,Clk2.Time('Hours'):13,
  471.     TimeFormat('h',stamp1):13, TimeFormat('h',stamp2):13,
  472.     TimeFormat('h',stamp3):13);
  473.   WRITELN ('hh:mm:ss.xx - L':26,         Clk2.Time('long'):13,
  474.     TimeFormat('L',stamp1):13, TimeFormat('L',stamp2):13,
  475.     TimeFormat('L',stamp3):13);
  476.   WRITELN ('minutes since midnight - M', Clk2.Time('minutes'):13,
  477.     TimeFormat('m',stamp1):13, TimeFormat('m',stamp2):13,
  478.     TimeFormat('m',stamp3):13);
  479.   WRITELN ('hh:mm:ss - N':26,            Clk2.Time('normal'):13,
  480.     TimeFormat('n',stamp1):13, TimeFormat('n',stamp2):13,
  481.     TimeFormat('n',stamp3):13);
  482.   WRITELN ('seconds since midnight - S', Clk2.Time('seconds'):13,
  483.     TimeFormat('s',stamp1):13, TimeFormat('s',stamp2):13,
  484.     TimeFormat('s',stamp3):13);
  485.  
  486.   WRITELN;
  487.   WRITELN ('Time Differences/Elapsed Time');
  488.   WRITELN ('-----------------------------');
  489.   WRITELN (' ':20,'seconds':12,'hh:mm:ss':16);
  490.   WRITELN ('CMOS - DOS Clock:':20,
  491.     TimeDiff(Clk2.StartValue,Clk3.StartValue):12:2,
  492.     hhmmss(TimeDiff(Clk2.StartValue,Clk3.StartValue)):16);
  493.   SetClock (1989,1, 1,  0, 0, 0,  0, stamp4);
  494.   SetClock (1990,1, 1,  0, 0, 0,  0, stamp5);
  495.   WRITELN ('Jan 1-Dec 31 1989:':20,TimeDiff(stamp5,stamp4):12:0,
  496.     hhmmss(TimeDiff(stamp5,stamp4)):16);
  497.   WRITELN ('Dec 31-Jan 1 1989:':20,TimeDiff(stamp4,stamp5):12:0,
  498.     hhmmss(TimeDiff(stamp4,stamp5)):16);
  499.   SetClock (1992,1, 1,  0, 0, 0,  0, stamp4);
  500.   SetClock (1993,1, 1,  0, 0, 0,  0, stamp5);
  501.   WRITELN ('1992 (leap year):':20,TimeDiff(stamp5,stamp4):12:0,
  502.     hhmmss(TimeDiff(stamp5,stamp4)):16);
  503.   SetClock (2000,1, 1,  0, 0, 0,  0, stamp5);
  504.   WRITELN ('20th century:':20,TimeDiff(stamp5,stamp2):12:0,
  505.     hhmmss(TimeDiff(stamp5,stamp2)):16,' (100*365 days + 24 leap days)');
  506.   WRITELN ('Maximum Clock Range:':20,TimeDiff(stamp3,stamp2):12:0,
  507.     hhmmss(TimeDiff(stamp3,stamp2)):16,' (January 1, 1900 midnight -');
  508.   WRITELN ('June 5, 2079 23:59:59.99)':78);
  509.   WRITELN ('Elapsed time:':20,Clk1.Elapsed:12:0,
  510.     hhmmss(Clk1.Elapsed):16);
  511.  
  512.   Readkey;
  513.   WRITELN;
  514.   WRITELN ('Clocks.UnPackTime');
  515.   WRITELN ('-----------------');
  516.   FindFirst ('*.*',AnyFile,DirInfo);
  517.   WHILE DOSError = 0 DO BEGIN  {Note:  seconds on files are even numbers}
  518.     Clocks.UnPackTime (DirInfo.Time, stamp5);
  519.     WRITELN (DirInfo.Name:12,'  ',DirInfo.size:7,'  ',
  520.       COPY(DateFormat('Weekday',stamp5),1,3),' ',
  521.       DateFormat('USA',stamp5),' ',TimeFormat('Normal',stamp5));
  522.     FindNext (DirInfo)
  523.   END;
  524.   Readkey;
  525. END {ClkDemo}.
  526.